package com.jacen.aws.client;

import com.alibaba.fastjson.JSON;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.*;
import com.jacen.aws.entity.KeyEntity;
import com.jacen.aws.entity.vo.AddressVo;
import com.jacen.aws.entity.vo.InstanceVo;
import com.jacen.aws.exception.ClientException;
import com.jacen.aws.setting.Setting;
import com.jacen.aws.util.StringUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * 版权声明：Copyright(c) 2018 All Rights Reserved.
 *
 * @Author Jacen (295117485@qq.com)
 * @Date 2018/10/13 8:33
 * @Version 1.0
 * @Description ec2 client
 */
public class Ec2Client {

    /**
     * 获取AmazonEC2 client
     *
     * @param keyEntity
     * @return
     * @throws ClientException
     */
    public static AmazonEC2 getEc2Client(KeyEntity keyEntity) throws ClientException {
        if (keyEntity == null) {
            throw new ClientException("密钥配置不能为空");
        }

        String accessKey = keyEntity.getAccessKey();
        String secretKey = keyEntity.getSecretKey();
        String region = keyEntity.getRegion();
        if (StringUtil.isEmpty(accessKey) || StringUtil.isEmpty(secretKey)) {
            throw new ClientException("密钥不能为空");
        }
        BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
        return AmazonEC2ClientBuilder.standard()
                .withCredentials(new AWSStaticCredentialsProvider(credentials))
                .withRegion(region == null ? Setting.REGION : region)
                .build();
    }

    /**
     * 获取实例信息
     *
     * @param keyEntity
     * @return
     * @throws ClientException
     */
    public static InstanceVo describeInstances(KeyEntity keyEntity) throws ClientException {
        AmazonEC2 client = getEc2Client(keyEntity);
        String insranceId = keyEntity.getInstanceId();
        DescribeInstancesRequest request = new DescribeInstancesRequest();
        List<String> list = new ArrayList<>();
        list.add(insranceId);
        request.setInstanceIds(list);
        DescribeInstancesResult result = client.describeInstances(request);
        List<Reservation> items = result.getReservations();
        Instance instance = items.get(0).getInstances().get(0);
        InstanceVo instanceVo = new InstanceVo();
        instanceVo.setCode(result.getSdkHttpMetadata().getHttpStatusCode());
        instanceVo.setPublicIp(instance.getPublicIpAddress());
        instanceVo.setRegion(instance.getPlacement().getAvailabilityZone());
        instanceVo.setInstanceId(insranceId);

        String ipOwnerId = instance.getNetworkInterfaces().get(0).getAssociation().getIpOwnerId();
        if (Setting.IP_OWNER_ID.equalsIgnoreCase(ipOwnerId)) {
            instanceVo.setElastic(Setting.ELASTIC_NO);
        } else {
            instanceVo.setElastic(Setting.ELASTIC_YES);
        }

        return instanceVo;
    }

    /**
     * 获取ip信息
     *
     * @param keyEntity
     * @return
     */
    public static AddressVo describeAddresses(KeyEntity keyEntity, String ip) {
        AmazonEC2 client = getEc2Client(keyEntity);
        DescribeAddressesRequest request = new DescribeAddressesRequest();
        List<String> list = new ArrayList<>();
        list.add(ip);
        request.setPublicIps(list);

        DescribeAddressesResult result = client.describeAddresses(request);
        AddressVo addressVo = new AddressVo();
        Address address = result.getAddresses().get(0);
        System.out.println(JSON.toJSONString(address));

        addressVo.setAllocationId(address.getAllocationId());
        addressVo.setPublicIp(address.getPublicIp());
        addressVo.setCode(result.getSdkHttpMetadata().getHttpStatusCode());

        if (!StringUtil.isEmpty(address.getInstanceId())) {
            addressVo.setUse(Setting.USE_YES);
        } else {
            addressVo.setUse(Setting.USE_NO);
        }
        return addressVo;
    }

    /**
     * 获取所有的ip地址信息
     *
     * @return
     */
    public static List<AddressVo> describeAddressList(KeyEntity keyEntity) {
        AmazonEC2 client = getEc2Client(keyEntity);
        try {
            DescribeAddressesResult result = client.describeAddresses();

            List<AddressVo> list = new ArrayList<>();
            AddressVo addressVo = null;
            for (Address address : result.getAddresses()) {
                addressVo = new AddressVo();

                addressVo.setAllocationId(address.getAllocationId());
                addressVo.setPublicIp(address.getPublicIp());
                addressVo.setCode(result.getSdkHttpMetadata().getHttpStatusCode());

                if (!StringUtil.isEmpty(address.getInstanceId())) {
                    addressVo.setUse(Setting.USE_YES);
                } else {
                    addressVo.setUse(Setting.USE_NO);
                }
                list.add(addressVo);
            }
            return list;
        } catch (Exception e) {
            throw new ClientException("获取ip地址异常：" + e.getMessage());
        }
    }

    /**
     * 分配弹性ip
     *
     * @return
     */
    public static AddressVo allocateAddress(KeyEntity keyEntity) throws ClientException {
        AmazonEC2 client = getEc2Client(keyEntity);
        try {
            AllocateAddressRequest request = new AllocateAddressRequest().withDomain("vpc");
            AllocateAddressResult result = client.allocateAddress(request);
            System.out.println("->allocate address http status code :" + result.getSdkHttpMetadata().getHttpStatusCode());
            System.out.println("->allocate address public ip :" + result.getPublicIp());
            System.out.println("->allocate address allocation id :" + result.getAllocationId());
            AddressVo addressVo = new AddressVo();
            addressVo.setCode(result.getSdkHttpMetadata().getHttpStatusCode());
            addressVo.setAllocationId(result.getAllocationId());
            addressVo.setPublicIp(result.getPublicIp());

            return addressVo;
        } catch (Exception e) {
            throw new ClientException("分配弹性ip异常", e);
        }
    }

    /**
     * 取消关联
     *
     * @param keyEntity
     * @param publicIp
     * @return
     * @throws ClientException
     */
    public static AddressVo disassociateAddress(KeyEntity keyEntity, String publicIp) throws ClientException {
        AmazonEC2 client = getEc2Client(keyEntity);
        try {
            DisassociateAddressRequest request = new DisassociateAddressRequest().withPublicIp(publicIp);
            DisassociateAddressResult result = client.disassociateAddress(request);
            System.out.println("->disassociate address http status code :" + result.getSdkHttpMetadata().getHttpStatusCode());
            AddressVo addressVo = new AddressVo();
            addressVo.setCode(result.getSdkHttpMetadata().getHttpStatusCode());
            addressVo.setPublicIp(publicIp);

            return addressVo;
        } catch (Exception e) {
            throw new ClientException("取消关联ip(" + publicIp + ")异常", e);
        }
    }

    /**
     * 根据ip地址释放弹性ip
     *
     * @param publicIp
     * @return
     */
    public static AddressVo releaseAddressRequestWithIp(KeyEntity keyEntity, String publicIp) throws ClientException {
        AmazonEC2 client = getEc2Client(keyEntity);
        try {
            ReleaseAddressRequest request = new ReleaseAddressRequest().withPublicIp(publicIp);
            ReleaseAddressResult result = client.releaseAddress(request);
            System.out.println("->release address http status code :" + result.getSdkHttpMetadata().getHttpStatusCode());
            AddressVo addressVo = new AddressVo();
            addressVo.setCode(result.getSdkHttpMetadata().getHttpStatusCode());
            addressVo.setPublicIp(publicIp);
            return addressVo;
        } catch (Exception e) {
            throw new ClientException("释放弹性ip(" + publicIp + ")异常", e);
        }

    }

    /**
     * 根据locationId释放弹性ip
     *
     * @param keyEntity
     * @param locationId
     * @return
     * @throws ClientException
     */
    public static AddressVo releaseAddressRequestWithLocationId(KeyEntity keyEntity, String locationId) throws ClientException {
        AmazonEC2 client = getEc2Client(keyEntity);
        try {
            ReleaseAddressRequest request = new ReleaseAddressRequest().withAllocationId(locationId);
            ReleaseAddressResult result = client.releaseAddress(request);
            System.out.println("->release address http status code :" + result.getSdkHttpMetadata().getHttpStatusCode());
            AddressVo addressVo = new AddressVo();
            addressVo.setCode(result.getSdkHttpMetadata().getHttpStatusCode());
            addressVo.setAllocationId(locationId);
            return addressVo;
        } catch (Exception e) {
            throw new ClientException("释放弹性ip(" + locationId + ")异常", e);
        }
    }

    /**
     * 关联弹性ip
     *
     * @param keyEntity
     * @param publicIp
     * @return
     * @throws ClientException
     */
    public static InstanceVo associateAddressRequest(KeyEntity keyEntity, String publicIp) throws ClientException {
        AmazonEC2 client = getEc2Client(keyEntity);
        String instanceId = keyEntity.getInstanceId();
        try {
            AssociateAddressRequest request = new AssociateAddressRequest().withInstanceId(instanceId).withPublicIp(publicIp);
            AssociateAddressResult result = client.associateAddress(request);
            System.out.println("->associate address http status code :" + result.getSdkHttpMetadata().getHttpStatusCode());

            InstanceVo instanceVo = new InstanceVo();
            instanceVo.setCode(result.getSdkHttpMetadata().getHttpStatusCode());
            instanceVo.setInstanceId(instanceId);
            instanceVo.setPublicIp(publicIp);

            return instanceVo;
        } catch (Exception e) {
            throw new ClientException("Ec2(" + instanceId + ")关联弹性ip(" + publicIp + ")异常:\n" + e.getMessage());
        }
    }
}
